/** JTalkerClientProtocol transmission protocol 
 *  @author ChrM */

package info.chrm.jtalker;
import info.chrm.helper.*;

public class JTalkerClientProtocol {
   /** Constructor */
   public JTalkerClientProtocol(JTalkerClient _parent) {
      this.parent = _parent;
   }

   /** Sends user status (must be set in the main class!) */
   public boolean sendUserStatus(boolean _sendPasswd) {
      String stream = "<JTALKER><MEMBER name=\"";
      stream += (this.parent.userName + "\" status=\"" + this.parent.userStatus + "\" ");
      if(_sendPasswd) {
	 // Create MD5-hash of password	
	 try { 
	    stream += ("passwd=\"" + MD5Password.hashPassword(this.parent.userPasswd + "\n") + "\" />");
	 } catch (Exception _e) {  
	    stream += ("passwd=\"\" />");
	 }
      }
      else
	 stream += "/>";
      stream += "</JTALKER>";
      
      return this.sendPackage(stream);
   }
 
   /** Send data for a new account */
   public boolean sendNewAccount(String _name, String _passwd) {
      String stream = "<JTALKER><NEW_MEMBER name=\"";
      stream += (_name + "\" ");
      // Create MD5-hash of password	
      try { 
	 stream += ("passwd=\"" + MD5Password.hashPassword(_passwd + "\n") + "\" />");
      } catch (Exception _e) {  
	 return false;
      }
      stream += "</JTALKER>";
      
      return this.sendPackage(stream);
   }

   /** Formats and sends a message (formated with HTML) */
   public boolean sendMessage(String _message, String _to, String _type, String _subject, String _id) {
      // prepare String
      try { 
	 _message = toHTMLString(_message);

	 if(_type == null)
	    _type = "normal";

         /*if(_type == "command")
             this.parent.setLastCommandResponse(null, null, null);*/
	
	 if(_to != null && (_to.indexOf(" AT ") != -1))
	    _to = _to.substring(0, _to.lastIndexOf(" AT "));

	 String stream = "<JTALKER><MESSAGE content=\"";
	 stream += (_message + "\" ");
	 if(_to != null)
	    stream += ("to=\"" + _to + "\" type=\"" + _type + "\"");
	 else
	    stream += ("type=\"" + _type + "\"");

         if(_id != null)
             stream += (" id=\"" + _id + "\"");
	 
	 if(_subject != null)
	    stream += (" subject=\"" + _subject + "\"");
	 
	 stream += " /></JTALKER>";

	 return this.sendPackage(stream);
      
      } catch (Exception e) { 
	 System.err.println("*** Can't send! " + e.toString());
	 return false;
      } 
   }

   /** Save rceived data */
   private boolean sendPackage(String _send) {
      return this.parent.sendToServer(_send);      
   }

   /** Process servers package */
   public boolean processServerPackage(String _package) {
      JTalkerParser tmpParser = new JTalkerParser();
      
      if(!tmpParser.parsing(_package))
         return false;
      
      /*if(tmpParser == null) {
	 System.err.println("*** Parser gets null!");
	 return false;
      }*/

      boolean updateUserList = false;

      // save member List
      try { 
	 //String server_message = tmpParser.getError();
	 String server_message = tmpParser.getAnswer();
	 if(server_message != null) {

	    if(tmpParser.getAnswerType() == JTalkerParser.ANSWER_ERROR) {
	       System.err.println("*** (GET) Error: " + server_message);
	       /// Only for the GUI-Version !!! Delete this for the console client!
               // TODO: make this message box not modal!!!
	       javax.swing.JOptionPane.showMessageDialog(null, 
							 "Server message:\n" + server_message, 
							 "Server answer (ERROR)", 
							 javax.swing.JOptionPane.ERROR_MESSAGE);
               
               if(this.parent.STATE == JTalkerClient.STATE_LOGGING || 
                  this.parent.STATE == JTalkerClient.STATE_ACCOUNT_CREATION) {
                   this.parent.closeConnection();
                   return true;
               }

	    } else if(tmpParser.getAnswerType() == JTalkerParser.ANSWER_INFO){
	       System.err.println("*** (GET) Info: " + server_message);
	       /// Only for the GUI-Version !!! Delete this for the console client!
               // TODO: make this message box not modal!!!
	       javax.swing.JOptionPane.showMessageDialog(null, 
							 "Server message:\n" + server_message, 
							 "Server answer (INFO)", 
							 javax.swing.JOptionPane.INFORMATION_MESSAGE);


	    } else if(tmpParser.getAnswerType() == JTalkerParser.ANSWER_UPDATE){
	       System.err.println("*** (GET) Update notification");
               this.sendUserStatus(false);

	    } else {
	       System.err.println("*** (GET) Undef: " + server_message);
	       /// Only for the GUI-Version !!! Delete this for the console client!
               // TODO: make this message box not modal!!!
	       javax.swing.JOptionPane.showMessageDialog(null, 
							 "Server message:\n" + server_message, 
							 "Server answer (UNDEFINED)", 
							 javax.swing.JOptionPane.INFORMATION_MESSAGE);
	    }
            
            // Close connection if we've got an answer for account creation   
            if(this.parent.STATE == JTalkerClient.STATE_ACCOUNT_CREATION) {
                   this.parent.closeConnection();
                   return true;
            }

	 }

         if(this.parent.STATE == JTalkerClient.STATE_LOGGING) {
               this.parent.STATE = JTalkerClient.STATE_CONNECTED;
         }

	 // Save Command Response
	 /*String tmpCommandResponse = tmpParser.getCommandResponse();
	 if(tmpCommandResponse != null) {
	    this.parent.setLastCommandResponse(tmpCommandResponse);
	 }*/
	 
	 for( int i = 0; i < tmpParser.getMemberNum(); i++ ) { 
	    this.parent.addMember(tmpParser.getAMember(i).name,
				  tmpParser.getAMember(i).status,
				  tmpParser.getAMember(i).type,
				  null,
				  tmpParser.getAMember(i).ip,
				  null,
				  null);

            if(!updateUserList)
                updateUserList = true;
	 }
	 // save messages
	 for( int i = 0; i < tmpParser.getMessagesNum(); i++ ) { 

            if(!tmpParser.getAMessage(i).messageType.equals("command_response")) {
                if(tmpParser.getAMessage(i).messageType.equals("command")) {
                    // TODO: send retval to caller
                    String retVal = this.parent.getFrontend().getPluginLoader().invokePlugInMethod(
                         tmpParser.getAMessage(i).content, 
                         tmpParser.getAMessage(i).sender);
                    
                    if(null == retVal) {    
                        String errMsg = this.parent.getFrontend().getPluginLoader().getLastError();
                        System.out.println("*** Can't invoke:" + errMsg);
                        this.parent.sendMessage(errMsg, tmpParser.getAMessage(i).sender, "error", null, tmpParser.getAMessage(i).id);
                    } else
                        this.parent.sendMessage(retVal, tmpParser.getAMessage(i).sender, "command_response", tmpParser.getAMessage(i).messageSubject, tmpParser.getAMessage(i).id);

                } else {
	            this.parent.addMember(tmpParser.getAMessage(i).sender,
                                      tmpParser.getAMessage(i).senderStatus,
                                      null,
                                      tmpParser.getAMessage(i).content,
                                      null,
                                      tmpParser.getAMessage(i).messageSubject,
                                      tmpParser.getAMessage(i).messageType);
                }
            } else {
                this.parent.setLastCommandResponse(tmpParser.getAMessage(i).id,
                                                   tmpParser.getAMessage(i).sender,
                                                   tmpParser.getAMessage(i).content);
            }
	 }

         if(updateUserList)
	    this.parent.cleanUpList(tmpParser);
	 
      } catch (Exception _e) { 
	 System.err.println("*** Protocol: Exception while parsing received data: " + _e.toString());
	 _e.printStackTrace();
	 return false;
      } 

      return true;
   }

   /**
    * Returns the specified string converted to a format suitable for
    * HTML. All signle-quote, double-quote, greater-than, less-than and
    * ampersand characters are replaces with their corresponding HTML
    * Character Entity code.
    *
    * @param in the String to convert
    * @return the converted String
    */
   public static String toHTMLString(String in) {
      StringBuffer out = new StringBuffer();
      for (int i = 0; in != null && i < in.length(); i++) {
	 char c = in.charAt(i);
	 if (c == '\'') {
	    out.append("&#39;");
	 }
	 else if (c == '\"') {
	    out.append("&#34;");
	 }
	 else if (c == '<') {
	    out.append("&lt;");
	 }
	 else if (c == '>') {
	    out.append("&gt;");
	 }
	 else if (c == '&') {
	    out.append("&amp;");
	 }
	 else if (c == '\n') {
	    out.append("_");
	 }
	 else if (c == '\r') {
	    out.append("_");
	 }
	 else {
	    out.append(c);
	 }
      }
      return out.toString();
   }
   
   private JTalkerClient parent;
}
